// (C) Copyright 2012 Kystar. All rights reserved.

`timescale 1ns/100ps
`default_nettype none

module net_audio_pkg 
#(parameter
    AUDIO_FIFO_DEPTH = 0
)
(
    input  wire          I_sclk,
    input  wire          I_rst_n,
    //
    output reg           O_req_net,
    input  wire          I_ack_net,
    //
    output reg           O_net_out_en,
    output reg  [ 7: 0]  O_net_out_data,
    //
    input  wire [ AUDIO_FIFO_DEPTH: 0] I_audio_fifo_usedw,
    output reg           O_audio_fifo_rdreq,
    input  wire [ 7: 0]  I_audio_fifo_q,
    //
    input  wire          I_disable_audio_pkg,
    // ram interface - 2048 Byte
    output reg  [ 7: 0]  O_pkg_ram_rdaddr,
    input  wire [ 7: 0]  I_pkg_ram_rddata,
    //
    input  wire          I_reg_audio_enable

);

/******************************************************************************
                                <localparams>
******************************************************************************/
localparam
    NET_HEAD_BYTES = 8,
    NET_UDP_BYTES  = 63 - 8;

localparam // state
    IDLE = 0,
    NET_REQ = 1,
    SEND_NET_HEAD = 1<<1,
    SEND_UDP_DATA = 1<<2,
    SEND_AUDIO_DATA = 1<<3,
    WAIT = 1<<4;

localparam
    AUDIO_FIFO_TH = 576;

/******************************************************************************
                              <internal signals>
******************************************************************************/
reg  [ 2: 0] head_cnt;
reg  [ 4: 0] state;
reg  [ 4: 0] next_state;
reg  [ 10: 0] data_cnt;
reg  [ 7: 0] udp_cnt;
reg  [ 9: 0] audio_fifo_rdreq_cnt;
reg  audio_fifo_rdreq_dly;
reg  [ 7: 0] audio_data;
reg  [ 7: 0] wait_cnt;

/******************************************************************************
                                <module body>
******************************************************************************/
// state machine : state
always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        state <= IDLE;
    else
        state <= next_state;

always @(*)
    case (state)
        IDLE:
            if (I_reg_audio_enable && !I_disable_audio_pkg && I_audio_fifo_usedw >= AUDIO_FIFO_TH)
                next_state = NET_REQ;
            else
                next_state = IDLE;
        NET_REQ:
            if (I_ack_net)
                next_state = SEND_NET_HEAD;
            else
                next_state = NET_REQ;
        SEND_NET_HEAD:
            if (head_cnt == NET_HEAD_BYTES - 1)
                next_state = SEND_UDP_DATA;
            else
                next_state = SEND_NET_HEAD;
        SEND_UDP_DATA:
            if (udp_cnt == NET_UDP_BYTES - 1)
                next_state = SEND_AUDIO_DATA;
            else
                next_state = SEND_UDP_DATA;
        SEND_AUDIO_DATA:
            if (data_cnt == AUDIO_FIFO_TH - 1)
                next_state = WAIT;
            else
                next_state = SEND_AUDIO_DATA;
        WAIT:
            if (wait_cnt == 255)
                next_state = IDLE;
            else
                next_state = WAIT;
        default:
            next_state = IDLE;
    endcase

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        wait_cnt <= 'd0;
    else if (state == WAIT)
        wait_cnt <= wait_cnt + 1'b1;
    else
        wait_cnt <= 'd0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_req_net <= 1'b0;
    else if (state == IDLE || state == WAIT)
        O_req_net <= 1'b0;
    else
        O_req_net <= 1'b1;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_net_out_en <= 1'b0;
    else if (state == SEND_NET_HEAD || state == SEND_AUDIO_DATA || state == SEND_UDP_DATA)
        O_net_out_en <= 1'b1;
    else
        O_net_out_en <= 1'b0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_net_out_data <= 8'h0;
    else if (state == SEND_NET_HEAD)
        begin
        if (head_cnt == NET_HEAD_BYTES - 1'b1)
            O_net_out_data <= 8'hD5;
        else
            O_net_out_data <= 8'h55;
        end
    else if (state == SEND_UDP_DATA)
        begin
        if (udp_cnt == NET_UDP_BYTES - 1 - 11)
            O_net_out_data <= 8'hAD;
        else
            O_net_out_data <= I_pkg_ram_rddata;
        end
    else if (state == SEND_AUDIO_DATA)
        O_net_out_data <= audio_data;
    else
        O_net_out_data <= 'd0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_pkg_ram_rdaddr <= 'd0;
    else if (state == SEND_NET_HEAD && head_cnt == NET_HEAD_BYTES - 'd2)
        O_pkg_ram_rdaddr <= 'd1;
    else if (state == SEND_NET_HEAD && head_cnt == NET_HEAD_BYTES - 1'b1)
        O_pkg_ram_rdaddr <= 'd2;
    else if (state == SEND_UDP_DATA)
        O_pkg_ram_rdaddr <= O_pkg_ram_rdaddr + 1'b1;
    else
        O_pkg_ram_rdaddr <= 'd0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        head_cnt <= 'd0;
    else if (state == SEND_NET_HEAD)
        head_cnt <= head_cnt + 1;
    else
        head_cnt <= 'd0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        udp_cnt <= 'd0;
    else if (state == SEND_UDP_DATA)
        udp_cnt <= udp_cnt + 1;
    else
        udp_cnt <= 'd0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        data_cnt <= 'd0;
    else if (state == SEND_AUDIO_DATA)
        data_cnt <= data_cnt + 1;
    else
        data_cnt <= 'd0;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        O_audio_fifo_rdreq <= 1'b0;
    else if (O_audio_fifo_rdreq && audio_fifo_rdreq_cnt == AUDIO_FIFO_TH - 1'b1)
        O_audio_fifo_rdreq <= 1'b0;
    else if (audio_fifo_rdreq_cnt == AUDIO_FIFO_TH)
        O_audio_fifo_rdreq <= 1'b0;
    else if (state == SEND_UDP_DATA && udp_cnt == NET_UDP_BYTES - 2)
        O_audio_fifo_rdreq <= 1'b1;
    else if (state == SEND_AUDIO_DATA)
        O_audio_fifo_rdreq <= 1'b1;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        audio_fifo_rdreq_cnt <= 'd0;
    else if (state == IDLE)
        audio_fifo_rdreq_cnt <= 'd0;
    else if (O_audio_fifo_rdreq)
        audio_fifo_rdreq_cnt <= audio_fifo_rdreq_cnt + 1'b1;

always @(posedge I_sclk or negedge I_rst_n)
    if (!I_rst_n)
        audio_fifo_rdreq_dly <= 1'b0;
    else
        audio_fifo_rdreq_dly <= O_audio_fifo_rdreq;

always @(posedge I_sclk)
    if (audio_fifo_rdreq_dly)
        audio_data <= I_audio_fifo_q;

endmodule
`default_nettype wire

